﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Dispatcher.Extensions
{
    /// <summary>
    /// Data Grid Extensions.
    /// </summary>
    public static class DataGridExtensions
    {
        /// <summary>
        /// Gets the visible row items.
        /// </summary>
        /// <param name="dataGrid">The data grid.</param>
        /// <returns>Visible row items.</returns>
        public static List<object> GetVisibleRowItems(this DataGrid dataGrid)
        {
            return dataGrid.GetVisibleRows().Select(r => r.Item).ToList();
        }

        /// <summary>
        /// Gets the visible rows.
        /// </summary>
        /// <param name="dataGrid">The data grid.</param>
        /// <returns>Visible rows.</returns>
        public static IList<DataGridRow> GetVisibleRows(this DataGrid dataGrid)
        {
            return dataGrid.GetVisualChildren<DataGridRow>();
        }

        /// <summary>
        /// Gets the visible cells.
        /// </summary>
        /// <param name="dataGrid">The data grid.</param>
        /// <returns>Visible cells.</returns>
        public static IList<DataGridCell> GetVisibleCells(this DataGrid dataGrid)
        {
            return dataGrid.GetVisualChildren<DataGridCell>();
        }

        /// <summary>
        /// Refreshes the data grid rows.
        /// </summary>
        /// <param name="dataGrid">The data grid.</param>
        public static void RefreshDataGridRows(this DataGrid dataGrid)
        {
            var rows = dataGrid.GetVisibleRows();
            dataGrid.RefreshDataGridRows(rows);
        }

        /// <summary>
        /// Refreshes the data grid rows.
        /// </summary>
        /// <param name="dataGrid">The data grid.</param>
        /// <param name="rows">The rows.</param>
        public static void RefreshDataGridRows(this DataGrid dataGrid, IEnumerable<DataGridRow> rows)
        {
            dataGrid.CancelEdit();

            foreach (var row in rows)
            {
                RefreshDataGridRow(row);
            }
        }

        /// <summary>
        /// Updates the data grid row.
        /// </summary>
        /// <param name="row">The row.</param>
        public static void RefreshDataGridRow(DataGridRow row)
        {
            var tmp = row.Item;
            row.Item = null;
            row.Item = tmp;
        }

        /// <summary>
        /// Gets the row.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public static DataGridRow GetRow(this DataGrid grid, int index)
        {
            var row = (DataGridRow) grid.ItemContainerGenerator.ContainerFromIndex(index);
            if (row == null)
            {
                // May be virtualized, bring into view and try again.
                grid.UpdateLayout();
                grid.ScrollIntoView(grid.Items[index]);
                row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
            }

            return row;
        }

        /// <summary>
        /// Gets the cell.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="row">The row.</param>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
        {
            if (row != null)
            {
                var presenter = row.GetVisualChildren<DataGridCellsPresenter>();

                if (presenter == null)
                {
                    grid.ScrollIntoView(row, grid.Columns[column]);
                    presenter = row.GetVisualChildren<DataGridCellsPresenter>();
                }

                var cell = (DataGridCell)presenter[column].ItemContainerGenerator.ContainerFromIndex(column);
                return cell;
            }

            return null;
        }

        /// <summary>
        /// Gets the cell.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="row">The row.</param>
        /// <param name="column">The column.</param>
        /// <returns></returns>
        public static DataGridCell GetCell(this DataGrid grid, int row, int column)
        {
            var rowContainer = grid.GetRow(row);
            return grid.GetCell(rowContainer, column);
        }
    }
}
